﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Drawing;

using Noris.Schedule.Support;
using Noris.Schedule.Support.Services;

namespace Noris.Schedule.Planning.Services
{
	// Tento soubor obsahuje výchozí paintery pro všechny podporované typy grafů a elementů.
	// Všechny paintery vracejí pro svůj okruh elementů hodnotu priority 0.25, 
	// čímž umožní dalším painterům při prioritě 1 je přehlasovat.
	#region DEFAULT PAINTER - pro vrstvu TempLayer
	/// <summary>
	/// Painter pro temporary elementy
	/// </summary>
	internal class PainterTempElements : IGraphElementPainter
	{
		float IGraphElementPainter.GetPriority(GraphElementPainterKey elementKey)
		{
			bool active = (elementKey.LayerType == GraphElementLayerType.TempLayer);
			return (active ? 0.25F : 0);
		}
		void IGraphElementPainter.Paint(GraphElementPainterArgs args)
		{
			// Vlastní prostor reprezentace grafu:
			args.DetailArea = args.DefaultDetailAreaElement;         // Vypočítat prostor pro detail
			args.BrushArea = args.RowGraphArea;                      // Prostor štětce = podle prostoru řádku
			args.VisualRectangle = args.DefaultVisualRectangle;      // Vizuální prostor je defaultní

			// Řeknu, co všechno chci vykreslit:
			args.BackGroundRunSystem = true;
			args.BackGroundRectangle = args.DetailArea;              // Prostor pro výplň
			// args.BackGroundColor = Color.Empty;                   // Když nenadefinuji barvu, vygeneruje se defaultní brush
		}
		void IGraphElementPainter.PaintAfter(GraphElementPainterArgs args)
		{ }
	}
	#endregion
	#region NÁHRADNÍ PAINTER - pokud se najde jiný element, a žádný painter se k němu nebude hlásit
	/// <summary>
	/// Painter zcela náhradní, priorita 0.10
	/// </summary>
	internal class PainterRefugeElements : IGraphElementPainter
	{
		float IGraphElementPainter.GetPriority(GraphElementPainterKey elementKey)
		{
			return 0.01F;
		}
		void IGraphElementPainter.Paint(GraphElementPainterArgs args)
		{
			// Vlastní prostor reprezentace grafu:
			args.DetailArea = args.DefaultDetailAreaElement;         // Vypočítat prostor pro detail
			args.BrushArea = args.RowGraphArea;                      // Prostor štětce = podle prostoru řádku
			args.VisualRectangle = args.DefaultVisualRectangle;      // Vizuální prostor je defaultní

			// Řeknu, co všechno chci vykreslit:
			args.BackGroundRunSystem = true;
			args.BackGroundRectangle = args.DetailArea;              // Prostor pro výplň
			args.BackGroundColor = Color.LightSlateGray;             // Když nenadefinuji barvu, vygeneruje se defaultní brush

			// Vypsat text:
            bool drawCaption = true; // bool drawCaption = args.GraphElement.IsDrawCaptionOnState(args.ElementState, args.GraphMode);
            if (drawCaption)
            {
                args.CaptionRunSystem = true;
                args.CaptionColor = Color.DarkBlue;
                args.CaptionText = "Painter nenalezen";
            }

            // Image:
            if (args.GraphElement.DataElement.Icon != null)
            {
                args.PaintImage = args.GraphElement.DataElement.Icon;
                args.PaintImageAtPoint = ContentAlignment.MiddleLeft;
                args.PaintImageAlignement = ContentAlignment.MiddleCenter;
            }
        }
		void IGraphElementPainter.PaintAfter(GraphElementPainterArgs args)
		{ }
	}
	#endregion
	#region DEFAULT PAINTER - pro elementy typu CapacityUtilization
	/// <summary>
	/// Painter pro CapacityUtilization elementy
	/// </summary>
	internal class PainterCapacityUtilizationElement : IGraphElementPainter
	{
		float IGraphElementPainter.GetPriority(GraphElementPainterKey elementKey)
		{
			bool active = ((elementKey.GraphMode == RowGraphMode.CapacityUtilization && elementKey.LayerType == GraphElementLayerType.ItemLayer)
				|| (elementKey.GraphMode == RowGraphMode.TaskCapacityLink && elementKey.LayerType == GraphElementLayerType.SubLayer));
			return (active ? 1 : 0);
		}
		void IGraphElementPainter.Paint(GraphElementPainterArgs args)
		{
			// Vlastní prostor reprezentace grafu, základna pro štětec, vizuální prostor:
			args.DetailArea = args.DefaultDetailAreaBack;            // Vypočítat prostor pro detail
			args.BrushArea = args.RowGraphArea;                      // Prostor štětce = podle prostoru řádku
			args.VisualRectangle = args.DefaultVisualRectangle;      // Vizuální prostor je defaultní

			// Vykreslení pozadí:
			args.BackGroundRunSystem = true;
			args.BackGroundRectangle = args.DetailArea;              // Prostor pro výplň
			args.BackGroundColor = (!args.DataElement.BackColor.IsEmpty ? args.DataElement.BackColor : Color.FromArgb(216, 240, 255));

			// Vykreslení CapacityUtilization je jen v příslušném grafu (ale tento painter obsluhuje dva různé grafy):
			if (args.ElementKey.GraphMode == RowGraphMode.CapacityUtilization)
			{
				args.VisualRectangle = args.DetailArea;              // V tomto prostoru se aktivuje ToolTip

				args.UtilizationRunSystem = true;
				args.UtilizationRectangle = args.DefaultDetailAreaElement;

				// Vykreslení horní linky:
				args.TopLineRunSystem = true;
				Rectangle utilRec = args.UtilizationRectangle;
				List<Point> polygon = new List<Point>();
				if (args.LastPoint.IsEmpty)
				{	// Čára ještě nezačala, začneme ji na začátku našeho řádku a dojedeme k naší X souřadnici:
					polygon.Add(new Point(args.RowGraphArea.X, utilRec.Bottom));
					polygon.Add(new Point(utilRec.X, utilRec.Bottom));
				}
				else if (args.LastPoint.X < utilRec.X)
				{	// Čára už někde běží, ale skončila vlevo od našeho levého okraje:
					polygon.Add(args.LastPoint);                                 // Navážu tam, kde skončila
					polygon.Add(new Point(args.LastPoint.X, utilRec.Bottom));    // Sjedu na jejím čase k nule
					polygon.Add(new Point(utilRec.X, utilRec.Bottom));           //  a dojedu na můj čas počátku v nulové souřadnici
				}
				else if (args.LastPoint.X == utilRec.X)
				{	// Čára skončila v tom čase, kdy já začínám:
					polygon.Add(args.LastPoint);                                 // Navážu tam, kde skončila
				}
				// Moj levý horní a pravý horní bod:
				polygon.Add(new Point(utilRec.X, utilRec.Y));
				polygon.Add(new Point(utilRec.Right, utilRec.Y));

				args.TopLinePolygon = polygon.ToArray();
				args.LastPoint = polygon[polygon.Count - 1];

			}

			// Boční okraje:
			args.BackSideRunSystem = true;
			args.BackSidePenColor = Color.DarkGreen;
			args.BackSideMinElementWidth = 30;
		}
		void IGraphElementPainter.PaintAfter(GraphElementPainterArgs args)
		{ }
	}
	#endregion
	#region DEFAULT PAINTER - pro graf Gantt a shape Rectangle
	/// <summary>
	/// Painter pro Hexagon elementy grafu Gantt
	/// </summary>
	internal class PainterGanttRectangleElement : IGraphElementPainter
	{
		float IGraphElementPainter.GetPriority(GraphElementPainterKey elementKey)
		{
			bool active = (elementKey.GraphMode == RowGraphMode.Gantt && elementKey.LayerType == GraphElementLayerType.ItemLayer
				&& elementKey.ElementShapeType == GraphElementShapeType.Rectangle);
			return (active ? 0.25F : 0);
		}
		void IGraphElementPainter.Paint(GraphElementPainterArgs args)
		{
			// Vlastní prostor reprezentace grafu:
			args.DetailArea = args.DefaultDetailAreaElement;         // Vypočítat prostor pro detail
			args.BrushArea = args.RowGraphArea;                      // Prostor štětce = podle prostoru řádku
			args.VisualRectangle = args.DefaultVisualRectangle;      // Vizuální prostor je defaultní

			// Pozadí:
			args.BackGroundRunSystem = true;
			args.BackGroundRectangle = args.DetailArea;
			// args.BackGroundColor = Color.LightSkyBlue;

			// Výplň podle sumáře časů:
			Rectangle detailArea = args.DetailArea;
			bool showFragment = (args.ElementState == GraphElementState.OnMouseFree || args.ElementState == GraphElementState.OnMousePinned || args.ElementState == GraphElementState.SelectedFree || args.ElementState == GraphElementState.SelectedPinned || args.ElementState == GraphElementState.ActiveFree || args.ElementState == GraphElementState.ActivePinned);
			if (showFragment && detailArea.Width > 7 && args.GraphElement.DataElement.Fragments != null)
			{

				float sumFragment = 0F;
				foreach (float fragment in args.GraphElement.DataElement.Fragments)
					sumFragment += fragment;
				if (sumFragment > 0F)
				{
					Rectangle fragmentBase = detailArea;
					float fW = (float)fragmentBase.Width - 6F;
					float fX = 3F;
					float top = (float)fragmentBase.Bottom - 5F;
					float height = 3F;
					float left = (float)fragmentBase.X + fX;
					float width = fW;
					float wkfc = width / sumFragment;
					Color[] colors = new Color[] { Color.Red, Color.LightCoral, Color.LightGreen, Color.Yellow };
					int colori = 0;
					foreach (float fragment in args.GraphElement.DataElement.Fragments)
					{
						float w = fragment * wkfc;
						RectangleF fragmentOne = new RectangleF(left, top, w, height);
						args.InnerShapeList.Add(new GraphElementPainterArgs.InnerShapeCls(Rectangle.Truncate(fragmentOne), colors[colori]));
						left += w;
						if ((++colori) >= colors.Length)
							colori = 0;
					}
				}
			}

			// Okraje pozadí:
			args.BackLineRunSystem = true;
			args.BackSidePenColor = Color.Black;
			args.BackLineWidth = 1;

			// Popisek:
            bool drawCaption = args.GraphElement.IsDrawCaptionOnState(args.ElementState, args.GraphMode);
            if (drawCaption)
            {
                args.CaptionRunSystem = true;
                args.CaptionColor = Color.Black;
            }

            // Image:
            if (args.GraphElement.DataElement.Icon != null)
            {
                args.PaintImage = args.GraphElement.DataElement.Icon;
                args.PaintImageAtPoint = ContentAlignment.MiddleLeft;
                args.PaintImageAlignement = ContentAlignment.MiddleCenter;
            }
        }
		void IGraphElementPainter.PaintAfter(GraphElementPainterArgs args)
		{ }
	}
	#endregion
	#region DEFAULT PAINTER - pro graf Gantt a shape Hexagon
	/// <summary>
	/// Painter pro Hexagon elementy grafu Gantt
	/// </summary>
	internal class PainterGanttHexagonElement : IGraphElementPainter
	{
		float IGraphElementPainter.GetPriority(GraphElementPainterKey elementKey)
		{
			bool active = (elementKey.GraphMode == RowGraphMode.Gantt && elementKey.LayerType == GraphElementLayerType.ItemLayer
				&& elementKey.ElementShapeType == GraphElementShapeType.Hexagon);
			return (active ? 0.25F : 0);
		}
		void IGraphElementPainter.Paint(GraphElementPainterArgs args)
		{
			// Vlastní prostor reprezentace grafu:
			args.DetailArea = args.DefaultDetailAreaElement;         // Vypočítat prostor pro detail
			args.BrushArea = args.RowGraphArea;                      // Prostor štětce = podle prostoru řádku
			args.VisualRectangle = args.DefaultVisualRectangle;      // Vizuální prostor je defaultní

			// Hexagon vykreslím pouze pro kladnou šířku:
			Rectangle detailArea = args.DetailArea;
			if (detailArea.Width > 0)
			{
				// Pozadí:
				args.BackGroundRunSystem = true;
				detailArea.Height = detailArea.Height - 1;

				// Hexagon vykreslím v závislosti na aktuální šířce prostoru:
				float fW = 0F;
				float fX = 0F;
				if (detailArea.Width <= 3)
				{	// Do 3 pixelů je to obdélník:
					args.BackGroundRectangle = detailArea;
				}
				else
				{	// Nad 3 pixely si obrazec spočítám:
					float dX = ((float)detailArea.Width - 2F) / 2F;
					float dY = dX * 3F;
					float dH = ((float)detailArea.Height) / 2F;
					if (dY < dH)
					{	// Obrazec má vlevo a vpravo tupý nos:
						int iX = (int)dX;
						int iY = (int)(Math.Round(dY, 0));
						args.BackGroundPolygon = new Point[] { 
							new Point(detailArea.X + iX, detailArea.Y),
							new Point(detailArea.Right - iX, detailArea.Y),
							new Point(detailArea.Right, detailArea.Y + iY),
							new Point(detailArea.Right, detailArea.Bottom - iY),
							new Point(detailArea.Right - iX, detailArea.Bottom),
							new Point(detailArea.X + iX, detailArea.Bottom),
							new Point(detailArea.X, detailArea.Bottom - iY),
							new Point(detailArea.X, detailArea.Y + iY),
							new Point(detailArea.X + iX, detailArea.Y) };
					}
					else
					{	// Obrazec má vlevo a vpravo ostrou špičku:
						dY = dH;
						dX = dY / 3F;
						int iX = (int)dX;
						int iY = (int)(Math.Round(dY, 0));
						args.BackGroundPolygon = new Point[] { 
							new Point(detailArea.X + iX, detailArea.Y), 
							new Point(detailArea.Right - iX, detailArea.Y),
							new Point(detailArea.Right, detailArea.Y + iY), 
							new Point(detailArea.Right - iX, detailArea.Bottom), 
							new Point(detailArea.X + iX, detailArea.Bottom), 
							new Point(detailArea.X, detailArea.Y + iY), 
							new Point(detailArea.X + iX, detailArea.Y) };
					}
					fX = dX + 2F;
					fW = (float)detailArea.Width - 2 * fX;
				}

				// Výplň podle sumáře časů:
				bool showFragment = (args.ElementState == GraphElementState.OnMouseFree || args.ElementState == GraphElementState.OnMousePinned || args.ElementState == GraphElementState.SelectedFree || args.ElementState == GraphElementState.SelectedPinned || args.ElementState == GraphElementState.ActiveFree || args.ElementState == GraphElementState.ActivePinned);
				if (showFragment && detailArea.Width > 7 && args.GraphElement.DataElement.Fragments != null)
				{
					float sumFragment = 0F;
					foreach (float fragment in args.GraphElement.DataElement.Fragments)
						sumFragment += fragment;
					if (sumFragment > 0F)
					{
						Rectangle fragmentBase = detailArea;
						float top = (float)fragmentBase.Bottom - 5F;
						float height = 3F;
						float left = (float)fragmentBase.X + fX;
						float width = fW;
						float wkfc = width / sumFragment;
						Color[] colors = new Color[] { Color.Red, Color.LightCoral, Color.LightGreen, Color.Yellow };
						int colori = 0;
						foreach (float fragment in args.GraphElement.DataElement.Fragments)
						{
							float w = fragment * wkfc;
							RectangleF fragmentOne = new RectangleF(left, top, w, height);
							args.InnerShapeList.Add(new GraphElementPainterArgs.InnerShapeCls(Rectangle.Truncate(fragmentOne), colors[colori]));
							left += w;
							if ((++colori) >= colors.Length)
								colori = 0;
						}
					}
				}

				// Okraje pozadí:
				args.BackLineRunSystem = true;
				args.BackLineColor = Color.Black;
				args.BackLineWidth = 1;

				// Popisek:
                bool drawCaption = args.GraphElement.IsDrawCaptionOnState(args.ElementState, args.GraphMode);
                if (drawCaption)
                {
                    args.CaptionRunSystem = true;
                    args.CaptionColor = Color.Black;
                }

                // Image:
                if (args.GraphElement.DataElement.Icon != null)
                {
                    args.PaintImage = args.GraphElement.DataElement.Icon;
                    args.PaintImageAtPoint = ContentAlignment.MiddleLeft;
                    args.PaintImageAlignement = ContentAlignment.MiddleCenter;
                }

				// Pokud je element Pinned, pak po vykreslení základu chci ještě zavolat zdejší metodu PaintAfter():
				if (args.GraphElement.IsPinned || args.GraphElement.IsBlocking)
					args.CallPaintAfter = true;
			}
		}
		void IGraphElementPainter.PaintAfter(GraphElementPainterArgs args)
		{
			if (args.GraphElement.IsPinned)
			{
				Point point = new Point(args.DetailArea.X + 1, args.DetailArea.Y + 0);
				args.PaintArgs.Graphics.DrawImage(PicLibrary22.Pin_red_Cached, point);
			}
			if (args.GraphElement.IsBlocking)
			{
				Point point = new Point(args.DetailArea.X + 1, args.DetailArea.Y + 0);
				args.PaintArgs.Graphics.DrawImage(PicLibrary22.Pin_red_Cached, point);
			}
		}
	}
	#endregion
	#region DEFAULT PAINTER - pro graf Gantt a shape RightTriangle
	/// <summary>
	/// Painter pro RightTriangle elementy grafu Gantt
	/// </summary>
	internal class PainterGanttRightTriangleElement : IGraphElementPainter
	{
		float IGraphElementPainter.GetPriority(GraphElementPainterKey elementKey)
		{
			bool active = (elementKey.GraphMode == RowGraphMode.Gantt && elementKey.LayerType == GraphElementLayerType.ItemLayer
				&& elementKey.ElementShapeType == GraphElementShapeType.RightTriangle);
			return (active ? 0.25F : 0);
		}
		void IGraphElementPainter.Paint(GraphElementPainterArgs args)
		{
			// Vstupní konstanty, definují tvar trojúhelníku:
			decimal widthRatio = 0.35M;        // Poměrná šířka trojúhelníku vzhledem k výšce
			decimal rightRatio = 0.65M;        // Poměr šířky trojúhelníku napravo od času End, vzhledem k šířce trojúhelníku (Height * widthRatio)

			// RightTriangle vykreslím jak pro kladnou, tak pro nulovou (i zápornou) šířku:
			Rectangle detailArea = args.DefaultDetailAreaElement;     // Vypočítat prostor pro detail
			detailArea.Height = detailArea.Height - 1;
			int iY = detailArea.Height / 2;                           // Polovina výšky 
			decimal tW = widthRatio * ((decimal)detailArea.Height);   // Šířka trojúhelníku = podle koeficientu
			decimal tR = tW * rightRatio;                             // Přesah trojúhelníku doprava od času End = podle koeficientu
			int iX = (int)(Math.Round(tW, 0));                        // Šířka trojúhelníku = int (v pixelech)
			int triaRight = (int)(Math.Round(tR, 0));                 // Přesah doprava přes okraj času konce = int (v pixelech)
			int elementRight = detailArea.Right + triaRight;          // Pozice Right trianglu = elementu
			int triaLeft = elementRight - iX;                         // Pozice levého pixelu trianglu, může / nemusí být uvnitř detailArea
			bool isTriangle = (triaLeft <= detailArea.X);             // true = je to trojúhelník, když triangl.Left <= element.Left
			detailArea.X = (isTriangle ? triaLeft : detailArea.Left); // Pozice levého pixelu elementu (to víc vlevo: detail / triangl)
			detailArea.Width = elementRight - detailArea.X;

			// Prostor pro reprezentaci grafu : upravím výchozí prostor podle zvětšených rozměrů elementu (detailArea):
			args.DetailArea = detailArea;
			args.BrushArea = _WideRectangle(args.RowGraphArea, detailArea);                  // Prostor štětce = podle prostoru řádku, rozšířený
			args.VisualRectangle = _WideRectangle(args.DefaultVisualRectangle, detailArea);  // Vizuální prostor je defaultní, rozšířený

			// Pozadí:
			args.BackGroundRunSystem = true;
			detailArea.Height = detailArea.Height - 1;

			// Element vykreslím buď jako trojúhelník nebo pětiúhelník (prasátko s hlavičkou doprava)
			if (isTriangle)
			{	// Trojúhelník:
				args.BackGroundPolygon = new Point[] { 
							new Point(detailArea.X, detailArea.Y),
							new Point(detailArea.Right, detailArea.Y + iY),
							new Point(detailArea.X, detailArea.Bottom),
							new Point(detailArea.X, detailArea.Y) };
			}
			else
			{	// Prasátko:
				args.BackGroundPolygon = new Point[] { 
							new Point(detailArea.X, detailArea.Y),
							new Point(detailArea.Right - iX, detailArea.Y),
							new Point(detailArea.Right, detailArea.Y + iY),
							new Point(detailArea.Right - iX, detailArea.Bottom),
							new Point(detailArea.X, detailArea.Bottom),
							new Point(detailArea.X, detailArea.Y) };
			}

			// Výplň podle sumáře časů:
			bool showFragment = (args.ElementState == GraphElementState.OnMouseFree || args.ElementState == GraphElementState.OnMousePinned || args.ElementState == GraphElementState.SelectedFree || args.ElementState == GraphElementState.SelectedPinned || args.ElementState == GraphElementState.ActiveFree || args.ElementState == GraphElementState.ActivePinned);
			if (showFragment && detailArea.Width > (iX + 8) && args.GraphElement.DataElement.Fragments != null)
			{
				float sumFragment = 0F;
				foreach (float fragment in args.GraphElement.DataElement.Fragments)
					sumFragment += fragment;
				if (sumFragment > 0F)
				{
					Rectangle fragmentBase = detailArea;
					float top = (float)fragmentBase.Bottom - 5F;
					float height = 3F;
					float left = (float)fragmentBase.X + 2;
					float width = detailArea.Width - iX - 2;
					float wkfc = width / sumFragment;
					Color[] colors = new Color[] { Color.Red, Color.LightCoral, Color.LightGreen, Color.Yellow };
					int colori = 0;
					foreach (float fragment in args.GraphElement.DataElement.Fragments)
					{
						float w = fragment * wkfc;
						RectangleF fragmentOne = new RectangleF(left, top, w, height);
						args.InnerShapeList.Add(new GraphElementPainterArgs.InnerShapeCls(Rectangle.Truncate(fragmentOne), colors[colori]));
						left += w;
						if ((++colori) >= colors.Length)
							colori = 0;
					}
				}
			}

			// Okraje pozadí:
			args.BackLineRunSystem = true;
			args.BackLineColor = Color.Black;
			args.BackLineWidth = 1;

			// Popisek:
			args.CaptionRunSystem = (detailArea.Width > 18);
			args.CaptionColor = Color.Black;

			// Pokud je element Pinned, pak po vykreslení základu chci ještě zavolat zdejší metodu PaintAfter():
			if (args.GraphElement.IsPinned || args.GraphElement.IsBlocking)
				args.CallPaintAfter = true;

		}
		/// <summary>
		/// Vrátí kombinaci defaultního prostoru (Y, Height) a rozšířeného prostoru (X, Width)
		/// </summary>
		/// <param name="defArea"></param>
		/// <param name="wideArea"></param>
		/// <returns></returns>
		private Rectangle _WideRectangle(Rectangle defArea, Rectangle wideArea)
		{
			return new Rectangle(wideArea.X, defArea.Y, wideArea.Width, defArea.Height);
		}
		void IGraphElementPainter.PaintAfter(GraphElementPainterArgs args)
		{
			if (args.GraphElement.IsPinned)
			{
				Point point = new Point(args.DetailArea.X + 1, args.DetailArea.Y + 0);
				args.PaintArgs.Graphics.DrawImage(PicLibrary22.Pin_red_Cached, point);
			}
			if (args.GraphElement.IsBlocking)
			{
				Point point = new Point(args.DetailArea.X + 1, args.DetailArea.Y + 0);
				args.PaintArgs.Graphics.DrawImage(PicLibrary22.Pin_red_Cached, point);
			}
		}
	}
	#endregion
	#region DEFAULT PAINTER - pro graf TaskCapacityLink a vrstvu ItemLayer
	/// <summary>
	/// Painter pro Item elementy grafu TaskCapacity
	/// </summary>
	internal class PainterTaskItemElement : IGraphElementPainter
	{
		float IGraphElementPainter.GetPriority(GraphElementPainterKey elementKey)
		{
			bool active = (elementKey.GraphMode == RowGraphMode.TaskCapacityLink && elementKey.LayerType == GraphElementLayerType.ItemLayer);
			return (active ? 0.25F : 0);
		}
		void IGraphElementPainter.Paint(GraphElementPainterArgs args)
		{
			// Vlastní prostor reprezentace grafu:
			args.DetailArea = args.DefaultDetailAreaElement;         // Vypočítat prostor pro detail
			args.BrushArea = args.RowGraphArea;                      // Prostor štětce = podle prostoru řádku
			args.VisualRectangle = args.DefaultVisualRectangle;      // Vizuální prostor je defaultní

			// Pozadí:
			args.BackGroundRunSystem = true;
			args.BackGroundRectangle = args.DetailArea;
			// args.BackGroundColor = Color.Beige;                   // Pokud bych tady definoval barvu, bude použita ona. Pokud nechám Empty, bude použita paleta.

			// Okraje pozadí:
			args.BackLineRunSystem = true;
			args.BackLineColor = Color.Black;
			args.BackLineWidth = 1;

			// Pokud je element v editoru (tzn. je propojen v síti vztahů), 
			//  bude mít výraznější okraje (dvojité) a část svého vnitřku věnuje právě těmto okrajům:
			if (args.ElementState == GraphElementState.InEditorFree || args.ElementState == GraphElementState.InEditorPinned)
			{
				Rectangle back = args.BackGroundRectangle;
				back.Y = back.Y + 1;
				back.Height = back.Height - 2;
				args.BackGroundRectangle = back;

				args.BackLineColor = Color.Yellow;
				args.BackLineWidth = 1;

				args.OuterLineRunSystem = true;
				args.OuterLineColor = Color.Magenta;
				args.OuterLineWidth = 4;
			}

			// Pokud jde o element v řádku, kde jsou použity fragmenty, pak element vykreslím poněkud lépe:
			if (args.RowContainFragments)
			{
				int minDim = 5;
				Rectangle back = args.BackGroundRectangle;
				Point lt = new Point(back.X, back.Y);                  // levý horní roh
				Point rt = new Point(back.Right - 1, back.Y);          // pravý horní roh
				Point rb = new Point(back.Right - 1, back.Bottom - 1); // pravý dolní roh
				Point lb = new Point(back.X, back.Bottom - 1);         // levý dolní roh
				if (args.BackGroundRectangle.Width >= minDim && args.BackGroundRectangle.Height >= minDim)
				{	// Při velikosti 4px a větší vykreslím element se zkosenými hranami
					// Připravím okraj oblasti, kde hrany budou zkosené o 1 pixel:
					// Podle BackGroundPolygon se vykreslí výplň:
					args.BackGroundPolygon = new Point[] {
						new Point(lt.X + 1, lt.Y),    // 0
						new Point(rt.X - 1, rt.Y),    // 1
						new Point(rt.X, rt.Y + 1),    // 2
						new Point(rb.X, rb.Y - 1),    // 3
						new Point(rb.X - 1, rb.Y),    // 4
						new Point(lb.X + 1, lb.Y),    // 5
						new Point(lb.X, lb.Y - 1),    // 6
						new Point(lt.X, lt.Y + 1),    // 7
						new Point(lt.X + 1, lt.Y) };  // 8
					args.BackGroundRectangle = Rectangle.Empty;

					// Totéž pole rozdělím na dva segmenty A a B, a vykreslím jeho obrysy dvěma barvami (A, B - viz níže, společné pro obě varianty):
					// Polygony A a B kreslí jen okraje (DrawLine), a nespojuje se automaticky první s posledním bodem (to by udělal DrawPolygon):
					args.BackGroundPolygonLineA = new Point[] {
						args.BackGroundPolygon[6],
						args.BackGroundPolygon[7],
						args.BackGroundPolygon[8],
						args.BackGroundPolygon[0],
						args.BackGroundPolygon[1],
						args.BackGroundPolygon[2] };

					args.BackGroundPolygonLineB = new Point[] {
						args.BackGroundPolygon[2],
						args.BackGroundPolygon[3],
						args.BackGroundPolygon[4],
						args.BackGroundPolygon[5],
						args.BackGroundPolygon[6] };
				}
				else
				{	// Při velikosti pod 4px sice nebudou zkosené hrany, ale bude použit 3D rámeček:
					args.BackGroundPolygonLineA = new Point[] { lb, lt, rt };
					args.BackGroundPolygonLineB = new Point[] { rt, rb, lb };
				}
				// Barva rámečku: A=světlá (levá a horní hrana), B=tmavá (pravá a dolní hrana):
				args.BackLineAColor = Color.FromArgb(236, 236, 216);
				args.BackLineBColor = Color.FromArgb(64, 64, 96);
			}

			// Popisek (=text uvnitř elementu) kreslit jen v aktivním grafu:
            bool drawCaption = args.GraphElement.IsDrawCaptionOnState(args.ElementState, args.GraphMode);
			if (drawCaption)
            {
				args.CaptionRunSystem = true;
				args.CaptionColor = Color.Black;
			}

            // Image:
            if (args.GraphElement.DataElement.Icon != null)
            {
                args.PaintImage = args.GraphElement.DataElement.Icon;
                args.PaintImageAtPoint = ContentAlignment.MiddleLeft;
                args.PaintImageAlignement = ContentAlignment.MiddleCenter;
            }

            // Pokud je element Pinned, pak po vykreslení základu chci ještě zavolat zdejší metodu PaintAfter():
			if (args.GraphElement.IsPinned || args.GraphElement.IsBlocking)
				args.CallPaintAfter = true;

		}
		void IGraphElementPainter.PaintAfter(GraphElementPainterArgs args)
		{
			if (args.GraphElement.IsPinned)
			{
				Point point = new Point(args.DetailArea.X + 1, args.DetailArea.Y + 0);
				args.PaintArgs.Graphics.DrawImage(PicLibraryIco.Pin_red_Cached, point);
			}
			if (args.GraphElement.IsBlocking)
			{
				Point point = new Point(args.DetailArea.X + 1, args.DetailArea.Y + 0);
				args.PaintArgs.Graphics.DrawImage(PicLibraryIco.Pin_red_Cached, point);
			}
		}
	}
	#endregion
}
